﻿// -------------------------------------------------------------------------
//    @FileName         :    CNVOtherEnterView.cpp
//    @Author           :    Gao.Yi
//    @Date             :    2025-09-28
//    @Email			:    445267987@qq.com
//    @Module           :    CNVOtherEnterView
//    @Desc             :
//
// -------------------------------------------------------------------------

#include "NFCityNormalViewFunc.h"

#include "NFCityMapUtil.h"
#include "NFCityPacketSendUtil.h"
#include "NFCityPlayer.h"
#include "NFCityPlayerUtil.h"

NFNVOtherEnterView::NFNVOtherEnterView(NFCityPlayer* pPlayer, NFCityNeighborGrid* pNeighborGrids)
{
    m_oCSRsp.mutable_map_enter_view_ntf()->set_reason(proto_ff::ENTER_VIEW_ALL);
    m_oCSRsp.mutable_map_enter_view_ntf()->set_map_id(pPlayer->GetMapDescId());

    m_pPlayer = pPlayer;
    m_pNeighborGrids = pNeighborGrids;
    m_bIsBreakIterate = false;
    m_iEnterViewCnt = 0;
    m_iCurGridIdx = -1;
    m_iGridViewNum = 0;
    m_bInTeam = m_pPlayer->GetTeamExt()->GetSize() > 0 ? true : false;
}

NFNVOtherEnterView::~NFNVOtherEnterView()
{
}

int NFNVOtherEnterView::DoFunc(NFCityWorldObject* pWorldObject)
{
    CHECK_NULL(0, pWorldObject);
    CHECK_NULL(0, m_pPlayer);
    if (pWorldObject->IsNpc())
    {
        if (pWorldObject->IsVisible(m_pPlayer))
        {
            EnterView(pWorldObject, 0);
        }
    }
    else if (pWorldObject->IsPlayer() && pWorldObject != m_pPlayer)
    {
        NFCityPlayer* pTargetPlayer = dynamic_cast<NFCityPlayer*>(pWorldObject);
        CHECK_NULL(0, pTargetPlayer);

        if (m_bInTeam)
        {
            if (NFCityPlayerUtil::IsPlayerInSameTeam(m_pPlayer, pTargetPlayer))
            {
                return 0;
            }
        }
        else
        {
            if ((int)m_stViewPlayerList.size() > m_pPlayer->GetViewList()->GetViewLeftNum())
            {
                m_bIsBreakIterate = true;
                return 0;
            }
        }

        if (pTargetPlayer->GetViewList()->IsEnterViewListFull())
        {
            return 0;
        }

        if (NFCityPlayerUtil::IsPlayerInTeam(pTargetPlayer))
        {
            if (NFCityPlayerUtil::IsPlayerTeamLeader(pTargetPlayer))
            {
                AddEnterPlayer(pTargetPlayer, 10);
            }
            else if (IsPlayerTeamLeaderInView(pTargetPlayer))
            {
                AddEnterPlayer(pTargetPlayer, 5);
            }
            else
            {
                AddEnterPlayer(pTargetPlayer, 1);
            }
        }
        else
        {
            AddEnterPlayer(pTargetPlayer, 5);
        }
    }

    return 0;
}

bool NFNVOtherEnterView::IsPlayerTeamLeaderInView(NFCityPlayer* pPlayer)
{
    NFCityPlayerTeamExt* pPlayerTeam = pPlayer->GetTeamExt();
    NFCityPlayer* pLeader = pPlayerTeam->GetLeader();
    if (pLeader)
    {
        int iLeaderGridID = pLeader->GetMapGridId();
        if (m_pNeighborGrids && m_pNeighborGrids->IsInNeighbor(iLeaderGridID))
        {
            return true;
        }
    }

    return false;
}

int NFNVOtherEnterView::AddEnterPlayer(NFCityPlayer* pPlayer, int iScore)
{
    CHECK_NULL(0, m_pPlayer);
    CHECK_NULL(0, pPlayer);
    if (m_stViewPlayerList.full())
    {
        LOG_TRACE(m_pPlayer->GetRoleID(), "view list is fulled! can't add player:{}", pPlayer->GetRoleID());
        return 0;
    }

    if (pPlayer->GetMapGridIdx() != m_iCurGridIdx)
    {
        m_iCurGridIdx = pPlayer->GetMapGridIdx();
        m_iGridViewNum = 0;
    }
    ++m_iGridViewNum;

    //mod score by player num in grid
    iScore = m_iGridViewNum > 5 ? (iScore + 5 - m_iGridViewNum) : iScore;

    m_stViewPlayerList.emplace(pPlayer->GetRoleID(), iScore);
    return 0;
}

int NFNVOtherEnterView::EnterView(NFCityWorldObject* pWorldObject, int iScore)
{
    CHECK_NULL(0, pWorldObject);
    CHECK_NULL(0, m_pPlayer);
    NFCityMapUtil::MakeEnterView(pWorldObject, m_oCSRsp.mutable_map_enter_view_ntf());
    ++m_iEnterViewCnt;
    if (pWorldObject->IsPlayer())
    {
        NFCityPlayer* pTargetPlayer = dynamic_cast<NFCityPlayer*>(pWorldObject);
        CHECK_NULL(0, pTargetPlayer);

        LOG_DEBUG(m_pPlayer->GetRoleID(), "player:{} enter player:{} view", pTargetPlayer->GetRoleID(), m_pPlayer->GetRoleID());

        if (m_pPlayer->GetViewList()->AddToViewList(pTargetPlayer->GetRoleID(), iScore) == 0)
        {
            pTargetPlayer->GetViewList()->AddToEnterViewList(m_pPlayer->GetRoleID());
        }

        if (!m_apViewPlayer.full())
        {
            m_apViewPlayer.push_back(pTargetPlayer);
        }
    }
    return 0;
}

int NFNVOtherEnterView::Send()
{
    CHECK_NULL(0, m_pPlayer);

    int iCount = 0;
    int iLeftNum = m_pPlayer->GetViewList()->GetViewLeftNum();
    m_stViewPlayerList.sort_list(std::greater<int>());

    for (auto iter = m_stViewPlayerList.begin(); iter != m_stViewPlayerList.end(); ++iter)
    {
        if (iCount >= iLeftNum)
        {
            break;
        }

        NFCityPlayer* pPlayer = NFCityPlayerUtil::GetPlayerByRoleID(iter->first);
        if (pPlayer)
        {
            EnterView(pPlayer, iter->second);
            ++iCount;
        }
    }

    if (m_pPlayer->IsEnterSvr() && m_iEnterViewCnt > 0)
    {
        NFCityPacketSendUtil::SendToClient(m_pPlayer, proto_ff::E_CS_MAP_ENTERVIEW_NTF, &m_oCSRsp);
    }

    for (int i = 0; i < (int)m_apViewPlayer.size(); ++i)
    {
        //syn action
        NFCityMapUtil::SynAction(m_apViewPlayer[i], m_pPlayer);
    }

    return 0;
}

NFNVEnterViewOther::NFNVEnterViewOther(NFCityPlayer* pPlayer)
{
    m_pPlayer = pPlayer;
    m_oCSRsp.mutable_map_enter_view_ntf()->set_reason(proto_ff::ENTER_VIEW_ALL);
    m_oCSRsp.mutable_map_enter_view_ntf()->set_map_id(pPlayer->GetMapDescId());

    //make view
    NFCityMapUtil::MakeEnterView(m_pPlayer, m_oCSRsp.mutable_map_enter_view_ntf());

    m_bIsAction = false;
    NFCityMapUtil::MakeLastAction(m_pPlayer, m_bIsAction, m_oCSActionRsp.mutable_map_action_ntf());

    m_bIsBreakIterate = false;
}

int NFNVEnterViewOther::DoFunc(NFCityWorldObject* pWorldObject)
{
    CHECK_NULL(0, pWorldObject);
    CHECK_NULL(0, m_pPlayer);

    if (pWorldObject->IsPlayer() && m_pPlayer != pWorldObject)
    {
        NFCityPlayer* pTargetPlayer = dynamic_cast<NFCityPlayer*>(pWorldObject);
        CHECK_NULL(0, pTargetPlayer);
        //is same team
        if (pTargetPlayer->GetTeamExt()->IsInTeam(m_pPlayer->GetRoleID()))
        {
            return 0;
        }

        if (m_pPlayer->GetViewList()->IsEnterViewListFull())
        {
            m_bIsBreakIterate = true;
            return 0;
        }

        if (pTargetPlayer->GetViewList()->IsViewListFull())
        {
            return 0;
        }

        //other team player
        if (m_pPlayer->GetTeamExt()->GetTeamMemberNum() > 0)
        {
            NFCityPlayer* pTeamLeader = m_pPlayer->GetTeamExt()->GetLeader();
            //other team leader
            if (m_pPlayer->GetTeamExt()->IsTeamLeader(m_pPlayer->GetRoleID()))
            {
                EnterViewOther(pTargetPlayer, 10);
            }
            //team leader is already in view
            else if (pTargetPlayer->GetViewList()->IsTeamLeaderInView(pTeamLeader))
            {
                EnterViewOther(pTargetPlayer, 5);
            }
            else if (!m_pPlayer->GetTeamExt()->IsTeamFollow(m_pPlayer->GetRoleID()))
            {
                EnterViewOther(pTargetPlayer, 5);
            }
        }
        //single player
        else
        {
            EnterViewOther(pTargetPlayer, 5);
        }
    }

    return 0;
}

int NFNVEnterViewOther::EnterViewOther(NFCityPlayer* pPlayer, int iScore)
{
    CHECK_NULL(0, m_pPlayer);
    CHECK_NULL(0, pPlayer);
    LOG_DEBUG(m_pPlayer->GetRoleID(), "player:{} enter player:{} view", m_pPlayer->GetRoleID(), pPlayer->GetRoleID());

    if (0 == pPlayer->GetViewList()->AddToViewList(m_pPlayer->GetRoleID(), iScore))
    {
        m_pPlayer->GetViewList()->AddToEnterViewList(pPlayer->GetRoleID());
    }

    if (pPlayer->IsEnterSvr())
    {
        NFCityPacketSendUtil::SendToClient(pPlayer, proto_ff::E_CS_MAP_ENTERVIEW_NTF, &m_oCSRsp);
        if (m_bIsAction)
        {
            NFCityPacketSendUtil::SendToClient(pPlayer, proto_ff::E_CS_MAP_ACTION_NTF, &m_oCSActionRsp);
        }
    }
    return 0;
}

int NFNVOtherLeaveView::DoFunc(NFCityWorldObject* pWorldObject)
{
    CHECK_NULL(0, pWorldObject);
    CHECK_NULL(0, m_pPlayer);
    if (pWorldObject->IsNpc())
    {
        NFCityMapUtil::MakeLeaveView(pWorldObject, m_oCSRsp.mutable_map_leave_view_ntf());
        ++m_iLeaveViewCnt;
    }
    else if (pWorldObject->IsPlayer())
    {
        NFCityPlayer* pTargetPlayer = dynamic_cast<NFCityPlayer*>(pWorldObject);
        CHECK_NULL(0, pTargetPlayer);
        if (m_pPlayer->GetViewList()->IsInViewList(pTargetPlayer->GetRoleID()))
        {
            m_pPlayer->GetViewList()->RemoveFromViewList(pTargetPlayer->GetRoleID());
            pTargetPlayer->GetViewList()->RemoveFromEnterViewList(m_pPlayer->GetRoleID());

            LOG_DEBUG(m_pPlayer->GetRoleID(), "player:{} leave player:{}", pTargetPlayer->GetRoleID(), m_pPlayer->GetRoleID());

            NFCityMapUtil::MakeLeaveView(pWorldObject, m_oCSRsp.mutable_map_leave_view_ntf());
            ++m_iLeaveViewCnt;
        }
    }

    return 0;
}

int NFNVOtherLeaveView::Send()
{
    if (m_pPlayer && m_pPlayer->IsEnterSvr() && m_iLeaveViewCnt)
    {
        NFCityPacketSendUtil::SendToClient(m_pPlayer, proto_ff::E_CS_MAP_LEAVEVIEW_NTF, &m_oCSRsp);
    }

    return 0;
}

NFNVLeaveViewOther::NFNVLeaveViewOther(NFCityPlayer* pPlayer)
{
    m_pPlayer = pPlayer;

    m_oCSRsp.mutable_map_leave_view_ntf()->set_reason(proto_ff::LEAVE_VIEW_OUT);

    //make leave view
    NFCityMapUtil::MakeLeaveView(pPlayer, m_oCSRsp.mutable_map_leave_view_ntf());
}

int NFNVLeaveViewOther::DoFunc(NFCityWorldObject* pWorldObject)
{
    CHECK_NULL(0, pWorldObject);
    CHECK_NULL(0, m_pPlayer);

    if (pWorldObject->IsPlayer() && m_pPlayer != pWorldObject)
    {
        NFCityPlayer* pTargetPlayer = dynamic_cast<NFCityPlayer*>(pWorldObject);
        CHECK_NULL(0, pTargetPlayer);

        LOG_DEBUG(m_pPlayer->GetRoleID(), "player:{} leave player:{} view", m_pPlayer->GetRoleID(), pTargetPlayer->GetRoleID());

        if (pTargetPlayer->GetViewList()->IsInViewList(m_pPlayer->GetRoleID()))
        {
            m_pPlayer->GetViewList()->RemoveFromEnterViewList(pTargetPlayer->GetRoleID());
            pTargetPlayer->GetViewList()->RemoveFromViewList(m_pPlayer->GetRoleID());

            LOGSVR_DEBUG("player:" << m_pPlayer->GetRoleID() << " leave player:" << pTargetPlayer->GetRoleID() << "view");

            if (!pTargetPlayer->IsEnterSvr())
            {
                return 0;
            }

            NFCityPacketSendUtil::SendToClient(pTargetPlayer, proto_ff::E_CS_MAP_LEAVEVIEW_NTF, &m_oCSRsp);
        }
    }

    return 0;
}


